/*
    Copyright 2009 Spencer B. Koehler, Ph.D.

    This file is part of the Brillig Toolkit.

    The Brillig Toolkit is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    The Brillig Toolkit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with The Brillig Toolkit.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.brillig.util.tree;


import org.brillig.util.DotMaker;

import java.io.IOException;
import java.io.Writer;
import java.util.List;

/**
 * Utility class for converting a tree to dot format.
 * <p>
 * Dot format is a text file representing a graph that can be turned
 * into an image using AT&amp;T's GraphViz project.
 * <p>
 * For example, the following command will turn a dot (text) file
 * generated by this utility into a png image.
 * <p>
 * dot -Tpng x.dot -o x.png
 *
 * @author Spence Koehler
 */
public class Tree2Dot <T> extends DotMaker {
  
  private Tree<T> tree;
  private TreeAnalyzer<T> treeAnalyzer;
  private LabelMaker<T> labelMaker;

  public Tree2Dot(Tree<T> tree) {
    this(tree, null, null);
  }

  public Tree2Dot(Tree<T> tree, TreeAnalyzer<T> treeAnalyzer, LabelMaker<T> labelMaker) {
    super();

    this.tree = tree;
    this.treeAnalyzer = treeAnalyzer;
    this.labelMaker = labelMaker;
  }

  protected final void populateEdges() {
    final int nodeId = addId2Label(tree);
    populateEdges(tree, nodeId);
  }

  private final int addId2Label(Tree<T> node) {
    return addId2Label(getLabel(node));
  }

  private final void populateEdges(Tree<T> node, int nodeId) {
    final List<Tree<T>> children = node.getChildren();

    if (children != null && children.size() > 0) {
      for (Tree<T> child : children) {
        final int childId = addId2Label(child);
        addEdge(nodeId, childId);
        populateEdges(child, childId);
      }
    }
  }

  private final String getLabel(Tree<T> node) {
    final T data = node.getData();
    final String result = (labelMaker == null) ? (data == null ? null : data.toString()) : labelMaker.makeLabel(node, treeAnalyzer);
    return (result == null) ? "<null>" : result;
  }

  public static interface LabelMaker <T> {
    public String makeLabel(Tree<T> node, TreeAnalyzer<T> treeAnalyzer);
  }

  public static void main(String[] args) throws IOException {
    if (args.length != 2) {
      System.out.println("Usage: Tree2Dot treeString outputFile");
    }
    else {
      final Tree<String> tree = TreeBuilderFactory.getStringTreeBuilder().buildTree(args[0]);
      final Writer writer = org.brillig.io.FileUtil.getWriter(args[1]);
      final Tree2Dot<String> tree2dot = new Tree2Dot<String>(tree);
      tree2dot.writeDot(writer);
      writer.close();
    }
  }
}
